package com.huatai.datacenter.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.huatai.common.api.R;
import com.huatai.common.httputil.HttpRequest;
import com.huatai.common.util.ObjectUtil;
import com.huatai.common.util.StringUtil;
import com.huatai.datacenter.entity.dataquality.QualityBaseEntity;
import com.huatai.datacenter.entity.dataquality.QualityLogDetailEntity;
import com.huatai.datacenter.entity.dataquality.QualityLogEntity;
import com.huatai.datacenter.entity.dataquality.QualityRuleEntity;
import com.huatai.datacenter.mapper.QualityRuleMapper;
import com.huatai.datacenter.service.QualityFunctionService;
import com.huatai.datacenter.service.QualityLogService;
import com.huatai.datacenter.service.QualityRuleService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
 * @author gusiyi
 * @version 1.0
 * @className QualityRuleServiceImpl
 * @description 描述：
 * @date 2023/6/1 10:48
 */
@Service
@Slf4j
public class QualityRuleServiceImpl extends ServiceImpl<QualityRuleMapper,QualityRuleEntity> implements QualityRuleService {

	@Autowired
	private QualityLogService qualityLogService;

	@Autowired
	private QualityFunctionService qualityFunctionService;

	@Override
	public Page<QualityRuleEntity> selectQualityRuleList(QualityRuleEntity qualityRuleEntity) {
		LambdaQueryWrapper<QualityRuleEntity> qualityRuleQuery = Wrappers.lambdaQuery();
		qualityRuleQuery
			.eq(QualityRuleEntity::getDeleted,false)
			.like(StringUtil.isNotBlank(qualityRuleEntity.getQualityRuleName()),QualityRuleEntity::getQualityRuleName,qualityRuleEntity.getQualityRuleName())
			.like(ObjectUtil.isNotEmpty(qualityRuleEntity.getQualityRuleTypeNum()),QualityRuleEntity::getQualityRuleTypeNum,qualityRuleEntity.getQualityRuleTypeNum())
			.orderByDesc(QualityBaseEntity::getUpdateTime);
		Page<QualityRuleEntity> page = new Page<>(qualityRuleEntity.getPageIndex(),qualityRuleEntity.getPageSize());
		return page(page, qualityRuleQuery);
	}

	@Override
	@Transactional(rollbackFor = {Exception.class})
	public boolean insertQualityRule(QualityRuleEntity qualityRuleEntity) {
		return save(qualityRuleEntity);
	}

	@Override
	@Transactional(rollbackFor = {Exception.class})
	public boolean updateQualityRule(QualityRuleEntity qualityRuleEntity) {
		return updateById(qualityRuleEntity);
	}

	@Override
	@Transactional(rollbackFor = {Exception.class})
	public boolean deleteByIds(List<QualityRuleEntity> qualityRuleEntityList) {
		for (QualityRuleEntity deleteEntity : qualityRuleEntityList) {
			deleteEntity.setDeleted(true);
		}
		return updateBatchById(qualityRuleEntityList);
	}

	@Override
	public boolean checkQualityRuleByFieldName(String sourceData, Long ruleId, Long dataModelId, String dataModelName, String fieldName, LocalDateTime executeTime,LocalDateTime nextExecuteTime) {
		QualityRuleEntity ruleEntity = getById(ruleId);
		if (1 == ruleEntity.getQualityRuleTypeNum()){
			//正则表达式
			boolean matches = sourceData.matches(ruleEntity.getMethodContent());
			if (matches){
				return matches;
			}else {
				QualityLogEntity logEntity = qualityLogService.getLogEntity(dataModelId,dataModelName);
				addErrLogDetail("不匹配",sourceData,ruleEntity,logEntity,fieldName,executeTime,nextExecuteTime);
				return false;
			}
		}else if (2 == ruleEntity.getQualityRuleTypeNum()){
			//内部api
			try {
				Class<? extends QualityFunctionService> functionClass = qualityFunctionService.getClass();
				String methodName = ruleEntity.getMethodContent();
				Method method = functionClass.getMethod(methodName, String.class);
				Map<String,Object> result = (Map<String,Object>) method.invoke(qualityFunctionService,sourceData);
				boolean data = (boolean)result.get("data");
				if (data){
					return data;
				}else {
					QualityLogEntity logEntity = qualityLogService.getLogEntity(dataModelId,dataModelName);
					addErrLogDetail((String)result.get("msg"),sourceData,ruleEntity,logEntity,fieldName,executeTime,nextExecuteTime);
					return false;
				}
			} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
				e.printStackTrace();
			}
		}else if (3 == ruleEntity.getQualityRuleTypeNum()){
			//外部api
			JSONObject body = new JSONObject();
			body.put("data",sourceData);
			Optional<R> resObj = HttpRequest
				.post(ruleEntity.getMethodContent())
				.bodyString(body.toJSONString())
				.execute()
				.onFailed((request, e) -> log.error("{}请求失败:{}",ruleEntity.getQualityRuleTypeName(),e.getMessage()))
				.onSuccessOpt(responseSpec -> responseSpec.asValue(R.class));
			R result = resObj.orElse(R.fail("未知错误"));
			boolean data = (boolean) result.getData();
			if (data){
				return data;
			}else {
				QualityLogEntity logEntity = qualityLogService.getLogEntity(dataModelId,dataModelName);
				addErrLogDetail(result.getMsg(),sourceData,ruleEntity,logEntity,fieldName,executeTime,nextExecuteTime);
				return false;
			}
		}
		return false;

	}

	/**
	 * 添加错误日志
	 * @param reason 错误原因
	 * @param sourceData 源数据
	 * @param ruleEntity 当前规则实体类
	 * @param logEntity 当前规则日志实体类
	 * @param fieldName 校验的字段名称
	 * @param executeTime 本次执行时间
	 * @param nextExecuteTime 下次执行时间
	 */
	private void addErrLogDetail(String reason,String sourceData,QualityRuleEntity ruleEntity,QualityLogEntity logEntity,String fieldName,LocalDateTime executeTime,LocalDateTime nextExecuteTime){
		QualityLogDetailEntity logDetailEntity = new QualityLogDetailEntity();
		logDetailEntity.setQualityLogId(logEntity.getId());
		logDetailEntity.setQualityRuleId(ruleEntity.getId());
		logDetailEntity.setQualityRuleName(ruleEntity.getQualityRuleName());
		logDetailEntity.setFieldName(fieldName);
		logDetailEntity.setSourceData(sourceData);
		logDetailEntity.setRemark(ruleEntity.getQualityRuleTypeName()+"("+ruleEntity.getQualityRuleName()+"):"+ruleEntity.getMethodContent()+"校验失败，原因："+reason);
		logDetailEntity.setExecuteTime(executeTime);
		logDetailEntity.setNextExecuteTime(nextExecuteTime);
		qualityLogService.addErrLogDetail(logDetailEntity);
	}
}
